package logic

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"iris/db"
	"iris/server"
	"net/http"
	"strconv"
	"time"

	"github.com/gomodule/redigo/redis"
	"github.com/tidwall/gjson"
)

type GetuiConf struct {
	AppId        string `toml:"app_id"`
	AppKey       string `toml:"app_key"`
	AppSecret    string `toml:"app_secret"`
	MasterSecret string `toml:"master_secret"`
}

// 推送
func CidSend(post map[string][]string) interface{} {

	httpData := make(map[string]string)

	// 推送ID
	if len(post["pushId"][0]) == 0 {
		return server.ResponseErr(6000)
	}
	// 标题
	if len(post["title"][0]) == 0 {
		return server.ResponseErr(6000)
	}
	// 简介
	if len(post["intro"][0]) == 0 {
		return server.ResponseErr(6000)
	}
	// 备注
	if len(post["data"][0]) == 0 {
		return server.ResponseErr(6000)
	}

	// 接收数据
	httpData["cid"] = post["pushId"][0]
	httpData["title"] = post["title"][0]
	httpData["intro"] = post["intro"][0]
	httpData["payload"] = post["data"][0]

	// 配置文件名
	systemInfo := "system.json"

	// 获取配置信息
	system := server.GetFile(systemInfo)

	// 个推配置
	pushConf := make(map[string]string)
	pushConf["push_host"] = gjson.Get(system, "push.push_host").String()
	pushConf["push_appId"] = gjson.Get(system, "push.push_appId").String()
	pushConf["push_appKey"] = gjson.Get(system, "push.push_appKey").String()
	pushConf["push_masterSecret"] = gjson.Get(system, "push.push_masterSecret").String()

	// 获取token
	pushToken := getPushToken(pushConf)

	// 单推地址
	cidUrl := pushConf["push_host"] + pushConf["push_appId"] + "/push/single/cid"

	// cid
	var cid [1]string
	cid[0] = httpData["cid"]

	// audience
	audience := make(map[string]interface{})
	audience["cid"] = cid

	// strategy
	strategy := make(map[string]int)
	strategy["default"] = 1

	// settings
	settings := make(map[string]interface{})
	settings["ttl"] = 86400000
	settings["strategy"] = strategy

	// transmission
	transmission := make(map[string]interface{})
	transmission["title"] = httpData["title"]
	transmission["content"] = httpData["intro"]
	transmission["payload"] = httpData["payload"]
	transmissionByte, _ := json.Marshal(transmission)
	transmissionStr := string(transmissionByte)

	// push_message
	push_message := make(map[string]string)
	push_message["transmission"] = transmissionStr

	// notification
	notification := make(map[string]interface{})
	notification["title"] = httpData["title"]
	notification["body"] = httpData["intro"]
	notification["click_type"] = "startapp"

	// ups
	ups := make(map[string]interface{})
	ups["notification"] = notification

	// android
	android := make(map[string]interface{})
	android["ups"] = ups

	// alert
	alert := make(map[string]interface{})
	alert["title"] = httpData["title"]
	alert["body"] = httpData["intro"]

	// aps
	aps := make(map[string]interface{})
	aps["alert"] = alert
	aps["content-available"] = 0
	aps["sound"] = "default"

	// ios
	ios := make(map[string]interface{})
	ios["type"] = "notify"
	ios["payload"] = httpData["payload"]
	ios["aps"] = aps
	ios["auto_badge"] = "+1"

	// push_channel
	push_channel := make(map[string]interface{})
	push_channel["android"] = android
	push_channel["ios"] = ios

	// 发送的数据
	sendInfoStr := make(map[string]interface{})

	sendInfoStr["request_id"] = server.Mmd5(strconv.FormatInt(time.Now().UnixNano(), 10))
	sendInfoStr["audience"] = audience
	sendInfoStr["settings"] = settings
	sendInfoStr["push_message"] = push_message
	sendInfoStr["push_channel"] = push_channel

	// 转json
	sendJson, _ := json.Marshal(sendInfoStr)

	// 发送推送
	result := SendPost(cidUrl, pushToken, sendJson)

	// 返回数据
	resultMap := make(map[string]int)
	json.Unmarshal([]byte(result), &resultMap)

	// 返回结果
	if resultMap["code"] == 0 {
		resData := make(map[string]interface{})
		json.Unmarshal([]byte(result), &resData)
		return server.ResponseJson(resData)
	} else {
		return server.ResponseErr(7001)
	}
}

// 获取token
func getPushToken(pushConf map[string]string) string {

	// 配置文件名
	systemInfo := "system.json"

	// 获取配置信息
	system := server.GetFile(systemInfo)

	// redis前缀
	redis_prefix := gjson.Get(system, "core.redis_prefix").String()

	// 获取token
	redigo := db.Redis()
	redis_token_key := redis_prefix + "_push_token"
	pushToken, _ := redigo.Do("Get", redis_token_key)
	pushTokenStr, _ := redis.String(pushToken, nil)
	if len(pushTokenStr) > 0 {
		return pushTokenStr
	}

	// token签名
	ms := time.Now().UnixNano() / 1e6
	timestamp := strconv.FormatInt(ms, 10)
	signStr := pushConf["push_appKey"] + timestamp + pushConf["push_masterSecret"]
	sign := server.Msha256(signStr)

	// 获取token地址
	tokenUrl := pushConf["push_host"] + pushConf["push_appId"] + "/auth"

	// 数据
	sendData := make(map[string]string)
	sendData["sign"] = sign
	sendData["timestamp"] = timestamp
	sendData["appkey"] = pushConf["push_appKey"]

	// map转json
	sendDataJson, _ := MakeReqBody(sendData)

	//创建客户端实例
	client := &http.Client{
		Timeout: 10 * time.Second,
	}

	body := bytes.NewBuffer(sendDataJson)

	//创建请求实例
	req, _ := http.NewRequest("POST", tokenUrl, body)

	req.Header.Add("Charset", "UTF-8")
	req.Header.Add("Content-Type", "application/json")

	//发起请求
	resp, _ := client.Do(req)

	defer resp.Body.Close()

	// 读取响应
	result, _ := ioutil.ReadAll(resp.Body)

	resultMap := make(map[string]int)
	json.Unmarshal(result, &resultMap)

	// 返回结果
	if resultMap["code"] == 0 {

		token := gjson.Get(string(result), "data.token").String()

		// 存储token
		redigo := db.Redis()
		redigo.Do("SET", redis_token_key, token)
		redigo.Do("EXPIRE", redis_token_key, 600)

		return token

	} else {
		return ""
	}
}

// post请求
func SendPost(url string, token string, sendJson []byte) string {

	//创建客户端实例
	client := &http.Client{
		Timeout: 10 * time.Second,
	}

	body := bytes.NewBuffer(sendJson)

	//创建请求实例
	req, _ := http.NewRequest("POST", url, body)

	req.Header.Add("token", token)
	req.Header.Add("Charset", "UTF-8")
	req.Header.Add("Content-Type", "application/json")

	//发起请求
	resp, _ := client.Do(req)

	defer resp.Body.Close()

	//读取响应
	result, _ := ioutil.ReadAll(resp.Body)

	return string(result)
}

//生成请求参数对应的JSON
func MakeReqBody(param interface{}) ([]byte, error) {

	body, err := json.Marshal(param)
	if err != nil {
		return nil, err
	}

	return body, nil
}
